package net.telesing.tcmc.core.entity;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;

import net.telesing.tcmc.core.StringUtil;
import net.telesing.tcmc.core.impl.Util;
import net.telesing.tcmc.core.utils.FileUtil;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import sun.misc.BASE64Decoder;

/**
 * 密钥工具类（具体实现）
 *
 * Created by Zmt on 2015/11/27.
 */
public class KeyEntity implements Util
{
    public KeyEntity()
    {
        initCipher();
    }
    
    private static final Logger log = LogManager.getLogger(KeyEntity.class);

    private static Cipher cipher = null;

    /**
     * 初始化Cipher
     */
    private void initCipher()
    {
        if (null == cipher)
        {
            try
            {
                cipher = Cipher.getInstance("RSA");
            }
            catch (NoSuchAlgorithmException e)
            {
                e.printStackTrace();
            }
            catch (NoSuchPaddingException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * 公钥加密
     *
     * @throws Exception
     */
    public byte[] publicEncrypt(String data, String publicPath) throws Exception
    {
        initCipher();

//        // 生成公钥和私钥
//        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//        KeyPair keyPair = keyPairGenerator.generateKeyPair();
//        PublicKey publicKey = keyPair.getPublic();
//        PrivateKey privateKey = keyPair.getPrivate();
//        saveKey(privateKey, "F:\\demo.key");  // 保存私钥到文件
//        // End

        PublicKey publicKey = getPublicKey(publicPath);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data.getBytes("UTF-8"));
//        saveData(cipher.doFinal(data.getBytes("UTF-8")), dataPath);  // 保存数据到文件
    }

    /**
     * 私钥解密
     *
     * @param keyPath
     * @param privatePath
     * @param password
     * @return
     * @throws Exception
     */
    public String privatecEncrypt(final String keyPath, final String privatePath, final String password) throws Exception
    {
        initCipher();
        PrivateKey privateKey = getPrivateKey(privatePath, password);
        byte[] key = new FileUtil().getUtil().readData(keyPath);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        String keyStr = new String(key, "UTF-8");
        return new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(keyStr.substring(StringUtil.getPosition(keyStr, "\\|", 3) + 1))), "UTF-8");
    }

    /**
     * 从文件中获取公钥
     *
     * @param path
     * @return
     */
    public PublicKey getPublicKey(final String path)
    {
        PublicKey result = null;
        try
        {
            CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
            X509Certificate cer = (X509Certificate) certificatefactory.generateCertificate(new FileInputStream(path));
            result = cer.getPublicKey();
//          new BASE64Encoder().encode(result.getEncoded());  // 转成字符串
        }
        catch (CertificateException e)
        {
            e.printStackTrace();
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从文件中获取私钥
     *
     * @param path 私钥证书文件路径
     * @param password 私钥证书密码
     * @return PrivateKey
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     * @throws IOException
     * @throws UnrecoverableKeyException
     */
    public PrivateKey getPrivateKey(final String path, final String password)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException
    {
        char[] nPassword;
        String keyAlias = null;
        KeyStore ks = KeyStore.getInstance("JKS");
        FileInputStream fis = null;
        try
        {
            fis = new FileInputStream(path);
            if (null == password || "".equals(password.trim()))
                nPassword = null;
            else
                nPassword = password.toCharArray();
            ks.load(fis, nPassword);
        }
        finally
        {
            if (null != fis)
                fis.close();
        }
        Enumeration<String> en = ks.aliases();
        if (en.hasMoreElements())
            keyAlias = en.nextElement();
        return (PrivateKey) ks.getKey(keyAlias, nPassword);
    }
    
}
